package com.business.exam.service.impl;

import com.business.common.constant.UserConstants;
import com.business.common.core.domain.AjaxResult;
import com.business.common.utils.DateUtils;
import com.business.common.utils.SecurityUtils;
import com.business.common.utils.StringUtils;
import com.business.exam.domain.ExamPaperModel;
import com.business.exam.domain.TextContent;
import com.business.exam.domain.enums.ExamPaperTypeEnum;
import com.business.exam.domain.exam.*;
import com.business.exam.domain.question.Question;
import com.business.exam.domain.question.QuestionEditRequestVM;
import com.business.exam.mapper.ExamPaperMapper;
import com.business.exam.mapper.QuestionMapper;
import com.business.exam.mapper.TextContentMapper;
import com.business.exam.service.IExamPaperService;
import com.business.exam.service.IQuestionService;
import com.business.exam.utils.DateTimeUtil;
import com.business.exam.utils.ExamUtil;
import com.business.exam.utils.JsonUtil;
import com.business.student.domain.PaperFilter;
import com.business.student.domain.PaperInfo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.time.LocalTime;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;

@Slf4j
@Service
public class ExamPaperServiceImpl implements IExamPaperService {

    @Autowired
    private ExamPaperMapper mapper;

    @Autowired
    private TextContentMapper textContentMapper;

    @Autowired
    private QuestionMapper questionMapper;

    @Autowired
    private IQuestionService questionService;

    @Transactional
    @Override
    public void saveOrEdit(ExamPaperEditRequestVM examPaperEditRequestVM) {
        Date now = new Date();
        List<ExamPaperTitleItemVM> titleItemsVM = examPaperEditRequestVM.getTitleItems();
        List<ExamPaperTitleItemObject> frameTextContentList = frameTextContentFromVM(titleItemsVM);
        String frameTextContentStr = JsonUtil.toJsonStr(frameTextContentList);

        List<String> deptIdList = mapper.getChileDeptIds(SecurityUtils.getDeptId());
        ExamPaperModel examPaper = null;

        // 插入数据
        if (examPaperEditRequestVM.getId() == null) {
            examPaper = new ExamPaperModel();

            BeanUtils.copyProperties(examPaperEditRequestVM, examPaper);
            // 插入题目JSON
            TextContent frameTextContent = new TextContent(frameTextContentStr, now);
            textContentMapper.insertSelective(frameTextContent);

            // 非管理员时
            if (!SecurityUtils.isAdmin(SecurityUtils.getUserId())) {
                examPaper.setDeptIds(deptIdList.stream().collect(Collectors.joining(",")));
            }
            // 插入试卷表
            examPaper.setFrameTextContentId(frameTextContent.getId());
            examPaper.setCreateTime(now);
            examPaper.setCreateUser(SecurityUtils.getUserId());
            examPaperFromVM(examPaperEditRequestVM, examPaper, titleItemsVM);
            mapper.insertData(examPaper);
            // ID不为空-时更新数据
        } else {
            // 更新题目相关表
            examPaper = mapper.selectDataById(examPaperEditRequestVM.getId());
            TextContent frameTextContent = textContentMapper.selectByPrimaryKey(examPaper.getFrameTextContentId());
            frameTextContent.setContent(frameTextContentStr);
            textContentMapper.updateByPrimaryKeySelective(frameTextContent);
            // 更新试卷表
            BeanUtils.copyProperties(examPaperEditRequestVM, examPaper);
            examPaperFromVM(examPaperEditRequestVM, examPaper, titleItemsVM);

            // 非管理员时
            if (!SecurityUtils.isAdmin(SecurityUtils.getUserId())) {
                examPaper.setDeptIds(deptIdList.stream().collect(Collectors.joining(",")));
            }

            mapper.updateData(examPaper);
        }
    }

    @Override
    public ExamPaperEditRequestVM findById(ExamPaperModel dto) {
        ExamPaperModel examPaper = null;
        if (dto.getId() != null) {
            examPaper = mapper.selectDataById(dto.getId());
            // 通过考试获取考试的试卷
        } else {
            examPaper = mapper.selectDataByExamId(dto.getExamMngId());
        }
        if (examPaper != null) {
            ExamPaperEditRequestVM vm = new ExamPaperEditRequestVM();
            BeanUtils.copyProperties(examPaper, vm);
            TextContent frameTextContent = textContentMapper.selectByPrimaryKey(examPaper.getFrameTextContentId());
            List<ExamPaperTitleItemObject> examPaperTitleItemObjects = JsonUtil.toJsonListObject(frameTextContent.getContent(), ExamPaperTitleItemObject.class);
            List<Integer> questionIds = examPaperTitleItemObjects.stream()
                    .flatMap(t -> t.getQuestionItems().stream()
                            .map(q -> q.getId()))
                    .collect(Collectors.toList());

            if (CollectionUtils.isEmpty(questionIds)) {
                questionIds = new ArrayList<>();
                questionIds.add(Integer.MAX_VALUE);
            }
            List<Question> questions = questionMapper.selectByIds(questionIds);

            List<ExamPaperTitleItemVM> examPaperTitleItemVMS = examPaperTitleItemObjects.stream().map(t -> {
                ExamPaperTitleItemVM tTitleVM = new ExamPaperTitleItemVM();
                BeanUtils.copyProperties(t, tTitleVM);
                List<QuestionEditRequestVM> questionItemsVM = t.getQuestionItems().stream().map(i -> {
                    Question question = questions.stream().filter(q -> q.getId().equals(i.getId())).findFirst().get();
                    QuestionEditRequestVM questionEditRequestVM = questionService.getQuestionEditRequestVM(question);
                    questionEditRequestVM.setItemOrder(i.getItemOrder());
                    return questionEditRequestVM;
                }).collect(Collectors.toList());
                tTitleVM.setQuestionItems(questionItemsVM);
                return tTitleVM;
            }).collect(Collectors.toList());
            vm.setTitleItems(examPaperTitleItemVMS);
            vm.setScore(ExamUtil.scoreToVM(examPaper.getScore()));
            vm.setPassScore(ExamUtil.scoreToVM(examPaper.getPassScore()));
            if (ExamPaperTypeEnum.TimeLimit == ExamPaperTypeEnum.fromCode(Integer.parseInt(examPaper.getPaperType()))) {
                List<String> limitDateTime = Arrays.asList(DateTimeUtil.dateFormat(examPaper.getLimitStartTime()), DateTimeUtil.dateFormat(examPaper.getLimitEndTime()));
                vm.setLimitDateTime(limitDateTime);
            }
            return vm;
        } else {
            return null;
        }

    }

    @Override
    public void updateById(Map<String, Object> paramMap) {
        List<String> idList = new ArrayList<>();
        // 设置更新参数
        if (paramMap.get("idArray") instanceof List) {
            idList.addAll((List) paramMap.get("idArray"));
        } else {
            idList.add(StringUtils.toString(paramMap.get("idArray")));
        }
        List<Map<String, Object>> updateList = new ArrayList<>();
        idList.forEach(data -> {
            Map<String, Object> dataMap = new HashMap<>();
            dataMap.put("mdfId", SecurityUtils.getUserId());
            dataMap.put("id", data);
            dataMap.put("delFlg", UserConstants.DEL_FLG_Y);
            updateList.add(dataMap);
        });
        paramMap.put("list", updateList);
        // 更新数据
        mapper.updateDataBatch(paramMap);
    }

    @Override
    public List<ExamPaperModel> findPage(ExamPaperModel dto) {
        // 分页查询数据
        dto.setDeptId(SecurityUtils.getDeptId());
        List<ExamPaperModel> resultList = mapper.selectPageList(dto);
        return resultList;
    }

    @Override
    public List<PaperInfo> indexPaper(PaperFilter paperFilter) {
        return mapper.indexPaper(paperFilter);
    }

    @Override
    public ExamPaperEditRequestVM examPaperToVM(Integer id) {
        ExamPaperModel examPaper = mapper.selectDataById(id);
        ExamPaperEditRequestVM vm = new ExamPaperEditRequestVM();
        BeanUtils.copyProperties(examPaper, vm);

        TextContent frameTextContent = textContentMapper.selectByPrimaryKey(examPaper.getFrameTextContentId());
        List<ExamPaperTitleItemObject> examPaperTitleItemObjects = JsonUtil.toJsonListObject(frameTextContent.getContent(), ExamPaperTitleItemObject.class);
        List<Integer> questionIds = examPaperTitleItemObjects.stream()
                .flatMap(t -> t.getQuestionItems().stream()
                        .map(q -> q.getId()))
                .collect(Collectors.toList());
        List<Question> questions = questionMapper.selectByIds(questionIds);
        List<ExamPaperTitleItemVM> examPaperTitleItemVMS = examPaperTitleItemObjects.stream().map(t -> {
            ExamPaperTitleItemVM tTitleVM = new ExamPaperTitleItemVM();
            BeanUtils.copyProperties(t, tTitleVM);
            List<QuestionEditRequestVM> questionItemsVM = t.getQuestionItems().stream().map(i -> {
                Question question = questions.stream().filter(q -> q.getId().equals(i.getId())).findFirst().get();
                QuestionEditRequestVM questionEditRequestVM = questionService.getQuestionEditRequestVM(question);
                questionEditRequestVM.setItemOrder(i.getItemOrder());
                return questionEditRequestVM;
            }).collect(Collectors.toList());
            tTitleVM.setQuestionItems(questionItemsVM);
            return tTitleVM;
        }).collect(Collectors.toList());
        vm.setTitleItems(examPaperTitleItemVMS);
        vm.setScore(ExamUtil.scoreToVM(examPaper.getScore()));
        if (ExamPaperTypeEnum.TimeLimit == ExamPaperTypeEnum.fromCode(Integer.parseInt(examPaper.getPaperType()))) {
            List<String> limitDateTime = Arrays.asList(DateTimeUtil.dateFormat(examPaper.getLimitStartTime()), DateTimeUtil.dateFormat(examPaper.getLimitEndTime()));
            vm.setLimitDateTime(limitDateTime);
        }
        return vm;
    }

    @Override
    public void logicDelete(Integer id) {
        ExamPaperModel dto = new ExamPaperModel();
        dto.setId(id);
        dto.setUpdateUser(SecurityUtils.getUserId());
        mapper.deleteById(dto);
    }

    @Override
    public AjaxResult generatePaper(ExamPaperAutoModel dto) {

        ExamPaperEditRequestVM examPaperEditRequestVM = new ExamPaperEditRequestVM();
        // 试卷类型
        examPaperEditRequestVM.setPaperType("1");
        // 试卷名称
        examPaperEditRequestVM.setName(dto.getPaperName());
        // 建议时间
        examPaperEditRequestVM.setSuggestTime(dto.getSuggestTime());
        // 合格分数
        examPaperEditRequestVM.setPassScore(dto.getPassScore());
        // 自动生成试题
        AjaxResult result = this.autoPaperTileItem(dto, examPaperEditRequestVM);
        if (result.isError()) {
            return result;
        }

        // 验证试卷是否存在
        ExamPaperModel model = new ExamPaperModel();
        model.setName(dto.getPaperName());
        int existsCnt = this.mapper.selectExistsCnt(model);
        if (existsCnt > 0) {
            return AjaxResult.error("考试名称[" + dto.getPaperName() + "]已经存在!");
        }

        // 保存试卷
        this.saveOrEdit(examPaperEditRequestVM);

        return AjaxResult.success();
    }

    /**
     * 自动生成实体
     */
    private AjaxResult autoPaperTileItem(ExamPaperAutoModel dto, ExamPaperEditRequestVM examPaperEditRequestVM) {
        // 初始化
        List<ExamPaperTitleItemVM> titleItems = new ArrayList<>();
        // 根据标签及数量获取随机的50道题
        Map<String, Object> queryMap = new HashMap<>();
        queryMap.put("categoryIds", dto.getGradeLevels());
        queryMap.put("limit", dto.getSingleCnt());
        queryMap.put("questionType", 1);
        this.setAllQuestionItem("单选题", queryMap, examPaperEditRequestVM, titleItems);
        if (examPaperEditRequestVM.getTitleItems().get(0).getQuestionItems().size() < dto.getSingleCnt()) {
            return AjaxResult.error("题库中的单选题数量不足" + dto.getSingleCnt() + "道!");
        }

        queryMap = new HashMap<>();
        queryMap.put("categoryIds", dto.getGradeLevels());
        queryMap.put("limit", dto.getMultipleCnt());
        queryMap.put("questionType", 2);
        this.setAllQuestionItem("多选题", queryMap, examPaperEditRequestVM, titleItems);
        if (examPaperEditRequestVM.getTitleItems().get(1).getQuestionItems().size() < dto.getMultipleCnt()) {
            return AjaxResult.error("题库中的多选题数量不足" + dto.getMultipleCnt() + "道!");
        }

        queryMap = new HashMap<>();
        queryMap.put("categoryIds", dto.getGradeLevels());
        queryMap.put("limit", dto.getTrueFalseCnt());
        queryMap.put("questionType", 3);
        this.setAllQuestionItem("判断题", queryMap, examPaperEditRequestVM, titleItems);
        if (examPaperEditRequestVM.getTitleItems().get(2).getQuestionItems().size() < dto.getTrueFalseCnt()) {
            return AjaxResult.error("题库中的判断题数量不足" + dto.getTrueFalseCnt() + "道!");
        }

        queryMap = new HashMap<>();
        queryMap.put("categoryIds", dto.getGradeLevels());
        queryMap.put("limit", dto.getShortAnswerCnt());
        queryMap.put("questionType", 5);
        this.setAllQuestionItem("简答题", queryMap, examPaperEditRequestVM, titleItems);
        if (examPaperEditRequestVM.getTitleItems().get(3).getQuestionItems().size() < dto.getShortAnswerCnt()) {
            return AjaxResult.error("题库中的简答题数量不足" + dto.getShortAnswerCnt() + "道!");
        }
        return AjaxResult.success();

    }

    /**
     * 获取题目共通方法
     *
     * @param name
     * @param queryMap
     * @param examPaperEditRequestVM
     */
    private void setAllQuestionItem(String name, Map<String, Object> queryMap, ExamPaperEditRequestVM examPaperEditRequestVM, List<ExamPaperTitleItemVM> titleItems) {
        List<QuestionEditRequestVM> questionEditRequestVMS = new ArrayList<>();
        ExamPaperTitleItemVM paperTitleItemVM = new ExamPaperTitleItemVM();
        paperTitleItemVM.setName(name);
        List<Integer> questionIdList = questionMapper.selectQuestionIdByLabel(queryMap);
        questionIdList.forEach(id -> {
            QuestionEditRequestVM questionEditRequestVM = questionService.getQuestionEditRequestVM(id);
            questionEditRequestVMS.add(questionEditRequestVM);
        });
        paperTitleItemVM.setQuestionItems(questionEditRequestVMS);
        titleItems.add(paperTitleItemVM);
        // 试题
        examPaperEditRequestVM.setTitleItems(titleItems);
    }

    private List<ExamPaperTitleItemObject> frameTextContentFromVM(List<ExamPaperTitleItemVM> titleItems) {
        AtomicInteger index = new AtomicInteger(1);
        return titleItems.stream().map(t -> {
            ExamPaperTitleItemObject titleItem = new ExamPaperTitleItemObject();
            BeanUtils.copyProperties(t, titleItem);
            List<ExamPaperQuestionItemObject> questionItems = t.getQuestionItems().stream()
                    .map(q -> {
                        ExamPaperQuestionItemObject examPaperQuestionItemObject = new ExamPaperQuestionItemObject();
                        BeanUtils.copyProperties(q, examPaperQuestionItemObject);
                        examPaperQuestionItemObject.setItemOrder(index.getAndIncrement());
                        return examPaperQuestionItemObject;
                    })
                    .collect(Collectors.toList());
            titleItem.setQuestionItems(questionItems);
            return titleItem;
        }).collect(Collectors.toList());
    }

    /**
     * 设置插入值
     *
     * @param examPaperEditRequestVM
     * @param examPaper
     * @param titleItemsVM
     */
    private void examPaperFromVM(ExamPaperEditRequestVM examPaperEditRequestVM, ExamPaperModel examPaper, List<ExamPaperTitleItemVM> titleItemsVM) {
        Integer questionCount = titleItemsVM.stream()
                .mapToInt(t -> t.getQuestionItems().size()).sum();
        Integer score = titleItemsVM.stream().
                flatMapToInt(t -> t.getQuestionItems().stream()
                        .mapToInt(q -> ExamUtil.scoreFromVM(q.getScore()))
                ).sum();
        examPaper.setQuestionCount(questionCount);
        examPaper.setScore(score);
        examPaper.setPassScore(ExamUtil.scoreFromVM(examPaperEditRequestVM.getPassScore()));
        List<String> dateTimes = examPaperEditRequestVM.getLimitDateTime();
        if (ExamPaperTypeEnum.TimeLimit == ExamPaperTypeEnum.fromCode(Integer.parseInt(examPaper.getPaperType()))) {
            examPaper.setLimitStartTime(DateTimeUtil.parse(dateTimes.get(0), DateTimeUtil.STANDER_FORMAT));
            examPaper.setLimitEndTime(DateTimeUtil.parse(dateTimes.get(1), DateTimeUtil.STANDER_FORMAT));
        }
    }
}
